home *** CD-ROM | disk | FTP | other *** search
/ Your Choice 3 / Your Choice Software Collection 3.iso / prgmming / swag08 / strings.swg < prev    next >
Text File  |  1994-09-22  |  92KB  |  1 lines

  1. SWAGOLX.EXE (c) 1993 GDSOFT  ALL RIGHTS RESERVED 00018                                                                           1      08-24-9413:21ALL                      TODD JACOBS              Basic-like Strings       SWAG9408    Ñ£º     14     ^&   {π  *****************************************************************π  *                         Basic Strings                         *π  *                               by                              *π  *                         Todd A. Jacobs                        *π  *                                                               *π  * Duplicates the Basic string functions Left$, Right$, and Mid$ *π  *****************************************************************ππ  A very simple unit to assist in parsing strings using familiarπ  Basic commands.  StrName is self-explanatory.  NumChars is theπ  length of the string to be returned, and StartPos is the index toπ  start at for the Mid$ (aka MidStr) function.ππ  Released into the public domain, I hope someone will: a) find itπ  useful, and b) add support for comma-delimited and space-delimitedπ  input (a la Basic).ππ  Comments may be directed to 1:109/182 or tjacobs@epub.com.π  Flames may be directed to the NUL device.  :)π}ππUnit BasicStr;ππInterfaceππFunction MidStr  ( StrName: String; StartPos, NumChars : Integer) : String;πFunction LeftStr ( StrName: String; NumChars : Integer) : String;πFunction RightStr( StrName: String; NumChars : Integer) : String;ππImplementationππFunction MidStr;πBeginπ  MidStr := Copy ( StrName, StartPos, NumChars);πEnd; {Mid$}ππFunction LeftStr;πBeginπ  LeftStr := Copy ( StrName, 1, NumChars);πEnd; {Left$}ππFunction RightStr;πBeginπ  RightStr := Copy ( StrName, ( Length(StrName) - (NumChars - 1)), NumChars);πEnd; {Right$}ππEnd. {Unit}π                                                                                                                        2      08-24-9413:28ALL                      SWAG SUPPORT TEAM        Clean String             SWAG9408    ▀Fφb    10     ^&   function Str2Int(Str:string): integer;πvarπ  temp,code : integer;πbeginπ  if length(Str) = 0 thenπ     Str2Int := 0π  else beginπ    val(Str,temp,code);π    if code = 0 thenπ       Str2Int := tempπ    elseπ       Str2Int := 0;π  end;πend;ππfunction StripFrontChars(Var S : String;Ch : Char) : String;πvarπ  S1 : String;πbeginπ  While (S[1] = Ch) and (Length(S) > 0) doπ  S := Copy(S,2,Length(S) - 1);π  StripFrontChars := Sπend;ππfunction StripBlanks(Var S : String) : String;πvarπ  i : Integer;πbeginπ  i := Length(S);π  while S[i] = ' ' do beginπ    Delete(S,i,1);π    Dec(i);π  end;π  StripBlanks := S;πend;ππfunction CleanString(var S: String): String;πbeginπ  StripFrontChars(S, #32);π  StripBlanks(S);πend;ππvarπ  S: String;π  i: Integer;πbeginπ  S := '   3   ';        { Create a bad string that will cause errors }π  CleanString(S);        { Clean it up                                }π  i := Str2Int(S);       { Convert                                    }π  WriteLn(i);            { Show it to the screen                      }πend.                                                                                                             3      08-24-9413:28ALL                      RICKY BOOTH              Adding Commas To Format  SWAG9408    Öïü┘    9      ^&   {π > says how big the file is it says it like 34443 and I wasπ > wonderingπ > is there a command or something I can add in TP6 to make it readπ > 34,443 where it detects where to add a commas. I know there isπ}πProgram Comma;ππUses Crt;ππVar x : longint;π    Y : string;ππFunction CommaNum ( I : LongInt ) : String;πVarπ    TmpString : String;π    Counter, Tester : Byte;πBeginπ  TmpString := '';π  Counter   := 0;π  Tester    := 0;π  Str (i, TmpString);π  For Counter := Length (TmpString) Downto 1 Doπ  Beginπ    Inc (Tester);π    If Tester = 3 Thenπ    Beginπ      Tester := 0;π      Dec (Counter);π      TmpString := Copy (TmpString, 1, Counter) + ','π                 + Copy (TmpString, Counter + 1, Length (TmpString) );π      Inc (Counter);π    End;π  End;π  If TmpString[1] = ',' THEN DELETE(TmpString,1,1);π  CommaNum := TmpString;πEnd;ππBeginπClrScr;πWrite('Enter a number ---> ');πReadln(x);πY := COMMANUM(X);πWrite('Here it is with COMMAS! ---> ');πWrite(y);πReadln;πEnd.π                                        4      08-24-9413:38ALL                      CHRIS PRIEDE             FLIPPING A STRING        SWAG9408    ╒¡╝    5      ^&   {π  Thanks but I already wrote a string flipping function, I asked for aπ  BASM or Assembler function for optimized speed.π}ππfunction FlipStr(S:string):string; ASSEMBLER;πASMπ        les     di,@Resultπ        mov     dx,dsπ        lds     si,Sπ        xor     ax,axπ        cldπ        lodsbπ        mov     [di],alπ        add     di,axπ        mov     cx,axπ        jcxz    @Doneπ@@1:    cldπ        lodsbπ        stdπ        stosbπ        loop    @@1π        mov     ds,dxπEND;πππ                           5      08-24-9413:45ALL                      JOSE CAMPIONE            Longints in Pascal       SWAG9408    YO┤W    25     ^&   π  typeπ    long = array[0..3] of byte;   {defines the fake-longint type}π    string8 = string[8];ππ  {translate the significant portion of a real into a long var}π  procedure real2long(r:real; var l:long; var e:boolean);π  typeπ    string8   = string[8];π    string32  = string[32];π  varπ    s : string32;ππ    function power(b:real; x:integer; var e:boolean): real;π    beginπ      if b > 0 then π        power:= exp(x * ln(b))π      else halt;π    end;ππ    {translate the significant portion of a real into a binary string32}π    procedure intreal2binstr(r:real; var s:string32; var e:boolean);π    varπ      i : integer;π      m : real;π      p : real;π    beginπ      e:= false;π      if (r > power(2,32,e)-1) then beginπ        e:= true;π        exit;π      end;π      s:= '';π      for i:= 31 downto 1 do beginπ        p:= power(2,i,e);π        m:= int(r/p);π        r:= r - (m * p);π        if (int(m) = 0)  then s:= s + '0'π                         else s:= s + '1';π      end;π      m:= int(r);π      r:= r - m;π      if (int(m) = 0) then s:= s + '0'π                      else s:= s + '1';π    end; ππ    {translate a binary string32 into a long variable}π    procedure binstr2long(s: string32; var l:long; var e:boolean);π    varπ      i : integer;π      w : string[8];π      b : byte;π  π      {translate a binary string8 into a byte}π      procedure binstr2byte(s:string8; var y:byte; var e:boolean);π      varπ        i   : integer;π        v   : integer;π        c   : integer;π        b   : byte;π      beginπ        y:= 0;π        for i:= 1 to 8 do beginπ          val(s[i],v,c);π          e:= not(c = 0);π          if e then exit;π          b:= v * trunc(power(2,(8-i),e));π          y:= y or b;π        end;π      end;ππ    begin  {binstr2long}π      for i:= 0 to 3 do beginπ        w:= copy(s,(i*8)+1,8);π        binstr2byte(w,b,e);π        l[3 - i]:= b;π      end;π    end;ππ  begin {real2long}π    intreal2binstr(r,s,e);π    if e then exit;π    binstr2long(s,l,e);π    if e then exit;π end;ππ  {translate a string8 (a number in hex notation) into a long variable} π  procedure str2long(s:string8; var l:long; var e: boolean);π  varπ    i : integer;π    c : integer;π    v : integer;π    sb : array[0..3] of string[3];π  beginπ    for i:= 0 to 3 do beginπ      sb[i]:= '$' + copy(s,(7-(i*2)),2);π      val(sb[i],v,c);π      e:= not(c = 0);π      if e then exit;π      l[i]:= v;π    end;π  end;ππ  {translate an integer into a long variable}π  procedure int2long(i:integer; var l: long);π  beginπ    fillchar(l,sizeof(l),0);π    move(i,l,2);π  end;ππ  {"shr 8" for long variables}π  procedure shr8(var a,b: long);π  varπ    i : integer;π  beginπ    for i:= 0 to 2 doπ      b[i]:= a[(i+1)];π    b[3]:= 0;π  end;ππ  {"xor" for long variables}π  procedure xorl(var a,b,c : long);π  varπ    i : integer;π  beginπ    for i:= 0 to 3 doπ      c[i]:= a[i] xor b[i];π  end;ππ  {"and" for long variables}π  procedure andl(var a,b,c : long);π  varπ    i : integer;π  beginπ    for i:= 0 to 3 doπ      c[i]:= a[i] and b[i];π  end;ππBEGINπEND.                   6      08-24-9413:49ALL                      MARIO POLYCARPOU         number conversion        SWAG9408    ·▄    19     ^&   {π JS> I, remember way back which could be a while I saw a basic routineπ JS> that would convert numbers to their written form like 120= oneπ JS> hundred and twenty. If anyone has such a routine it would beπ JS> appreciated..πππ This was quite a challenge..I did find a bug so have a look at theπ test. To really put this to the test you'd have to get it to returnπ every single number (0-64K) and observe the output.πππ{Returns the written format of any number between 0-65535}π{ Could be useful in a checkbook program }ππUSES Crt;ππ{----------------------------------------------------}πFUNCTION LZ(Num:Word; Times:Byte; Ch:Char):String;πVAR S:String;πBEGINπ Str(Num,S); WHILE Length(S)<Times DO S:=Ch+S; LZ:=S;πEND;π{------------------------------------------------}πFUNCTION Convert(Num:Word):String;πCONSTπ Hu='hundred'; Th='thousand';π Units:Array[0..9] OF String[5]=   {60 bytes}π ('','one','two','three','four','five','six','seven','eight','nine');π Tens:Array[0..9] OF String[7]=    {80 bytes}π ('','ten,','twenty','thirty','fourty','fifty','sixty','seventy','eighty',π 'ninety');π Ones:Array[0..9] OF String[9]=    {100 bytes}π ('','eleven','twelve','thirteen','fourteen','fifteen','sixteen',π  'seventeen','eighteen','nineteen');πVAR S1,S2:String; X:Byte;πBEGINπ S1:=LZ(Num,5,' '); S2:='';π FOR Num:=Length(S1) DOWNTO 1 DOπ  IF S1[Num]<>' ' THENπ   BEGINπ    X:=Ord(S1[Num])-48;π    CASE Num OFπ     1: S2:=Tens[X]+' '+S2;π     2: IF S1[1]='1' THENπ         BEGINπ          S2:=Ones[X]+' '+Th+' '+S2; Break;π         END ELSE S2:=Units[X]+' '+Th+' '+S2;π     3: IF S1[3]='0' THENπ         BEGINπ          IF (S1[2]<>'0') AND (S1[1]<>' ') THEN S2:='and '+S2;π         END ELSEπ          IF S1[4]<>'0' THEN S2:=Units[X]+' '+Hu+' and '+S2π           ELSE S2:=Units[X]+' '+Hu;π     4: S2:=Tens[X]+' '+S2;π     5: IF S1[4]='1' THENπ         BEGINπ          S2:=Ones[X]; Break;π         END ELSE S2:=Units[X];π    END;π   END; Convert:=S2;πEND;π{------------------------------------------------}πBEGINπ ClrScr;π Writeln(Convert(23452));     {ok}π Writeln(Convert(60201));    {Bug!}π Writeln(Convert(9900));      {ok}π Writeln(Convert(534));       {ok}π Writeln(Convert(18770));     {ok}π Writeln(Convert(4));         {ok}πEND.π                                                                        7      08-24-9413:51ALL                      GREG VIGNEAULT           PosIn()                  SWAG9408    ² ║═    30     ^&   {π Here's a routine that's faster than Pos on my system. It's writtenπ in external assembly language, and linked directly into TP programπ code.  I'm including an example of using the code, the assemblyπ source code, and a pre-assembled ready-to-compile POSIN.OBJ file:ππ Here's the example... }ππ(*******************************************************************)πPROGRAM Demo; { A faster Pos() for TP4+. June 17/94 Greg Vigneault  }ππVAR str : STRING;  j : BYTE;ππFUNCTION PosIn (Pattern, Str : STRING) : BYTE; EXTERNAL;π{$L POSIN.OBJ}    (* link in the external code *)ππBEGINπ      WriteLn;π      str := 'Position of THIS in string is ';π      j := PosIn ('THIS',str);;  WriteLn (str,j);π      WHILE (j > 1) DO BEGIN Write (' '); DEC(j); END;π      WriteLn ('^^^^');π      WriteLn;πEND.π(*******************************************************************)ππHere's the assembly code source...π;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;πcode    segment byte public 'CODE'π        assume  cs:codeπ; FUNCTION PosIn (pattern, string : STRING) : BYTE;πpattern equ dword ptr 8[bp]πstring  equ dword ptr 4[bp]πPosIn   proc    nearπ        public  PosInπ        push  bp                    ; preserveπ        mov   bp, spπ        push  dsπ        push  esπ        cld                         ; assure forward scansπ        lds   si, pattern           ; DS:SI -> patternπ        sub   ax, ax                ; zeroπ        lodsb                       ; get length byteπ        test  ax, ax                ; null string?π        jz    done                  ; yes: exit with zeroπ        mov   dx, ax                ; length of patternπ        les   di, string            ; ES:DI -> stringπ        sub   bx, bx                ; zeroπ        mov   bl, es:[di]           ; string lengthπ        cmp   bx, dx                ; pattern > string ?π        jc    none                  ; yes: exit with zeroπ        inc   di                    ; point to 1st string charπ        lodsb                       ; get pattern 1st charπ        dec   dx                    ; adjust pointerπ        sub   bx, dx                ; don't need to check endπ  po0:  mov   cx, bx                ; unsearched chars countπ        repne scasb                 ; search for pattern charπ        jne   none                  ; no char matchπ        mov   bx, cx                ; unsearched countπ        push  di                    ; save text pointersπ        push  siπ        mov   cx, dx                ; length of patternπ        repe  cmpsb                 ; check for patternπ        pop   si                    ; restore pointersπ        pop   diπ        jne   po0                   ; loop if no pattern matchπ        lds   ax, string            ; string pointerπ        xchg  ax, di                ; swap offsetsπ        sub   ax, di                ; subtract offsetsπ        dec   ax                    ; adjust for PosInπ        jmp   short done            ; found patternπ  none: sub   ax, ax                ; pattern not foundπ  done: pop   es                    ; restoreπ        pop   dsπ        mov   sp, bpπ        pop   bpπ        ret   8πPosIn   endpπcode    endsπ        endπ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ππUSE XX3402 to decode this and obtain POSIN.OBJ requried for this unit.ππ*XX3402-000140-170694--72--85-37398-------POSIN.OBJ--1-OF--1πU+g+0L-jQqZi9Y3HHHGK-k++-2BDF2J2a+Q+82U++U6-v7+A+++--J-DIoZC++++pMU2++0Wπ+R4UH++-++-JWykS-jn3RUUfk8m3k5EkWx12TUEfqmO85HjOQW-5f2cfqcj9wetp3MjNJpO9πmjCaLZxpvgJ4-7QfloXf+Wj+-ly9tJr00+1nWU6++5E+π***** END OF BLOCK 1 *****ππ                                                                                                       8      08-24-9413:51ALL                      EDDY THILLEMAN           Pos() in asm             SWAG9408    kC    23     ^&   πvarπ  s1, s2: string;π  position: byte;ππfunction StrPos( var str1, str2: string ): byte; assembler;π  { returns position of the first occurrence of str1 in str2 }π  { return value in AL }π  { str1 - string to search for }π  { str2 - string to search in  }πasmπ        CLD              { string operations forward                 }π        LES   DI,Str2    { load in ES:DI pointer to str2             }π        XOR   CH,CH      { clear CH                                  }π        MOV   CL,[DI]    { length str2 --> CL                        }π        AND   CL,CL      { length str2 = 0?                          }π        JZ    @Negatief  { length str2 = 0, nothing to search in     }π        MOV   BH,CL      { length str2 --> BH                        }π        INC   DI         { make DI point to the 1st char of str2     }π        LDS   SI,Str1    { load in DS:SI pointer to str1             }π        LODSB            { load in AL length str1                    }π        AND   AL,AL      { length str1 = 0?                          }π        JZ    @Negatief  { length str1 = 0, nothing to search for    }π        DEC   AL         { 1st char need not be compared again       }π        SUB   CL,AL      { length str2 - length str1                 }π        JBE   @Negatief  { length str2 < length str1                 }π        MOV   AH,AL      { length str1 --> AH                        }π        LODSB            { load in AL 1st character of str1          }π@Start:π  REPNE SCASB            { scan for next occurrence 1st char in str2 }π        JNE   @Negatief  { no success                                }π        MOV   DX,SI      { pointer to 2nd char in str1 --> DX        }π        MOV   BL,CL      { number of chars in str2 to go --> BL      }π        MOV   CL,AH      { length str1 --> CL                        }π   REPE CMPSB            { compare until characters don't match      }π        JE    @Positief  { full match                                }π        SUB   SI,DX      { current SI - prev. SI = # of chars moved  }π        SUB   DI,SI      { current DI - # of chars moved = prev. DI  }π        MOV   SI,DX      { restore pointer to 2nd char in str1       }π        MOV   CL,BL      { number of chars in str2 to go --> BL      }π        JMP   @Start     { scan for next occurrence 1st char in str2 }π@Negatief:π        XOR   AX,AX      { str1 is not in str2, result 0             }π        JMP   @Exitπ@Positief:π        ADD   BL,AH      { number of chars in str2 left              }π        MOV   AL,BH      { length str2 --> AX                        }π        SUB   AL,BL      { start position of str1 in str2            }π@Exit:                   { we are finished. }πend  { StrPos };ππbeginπ  s1 := ParamStr( 1 );π  s2 := ParamStr( 2 );π  writeln( StrPos( s1, s2 ) );πend.ππ        9      08-24-9413:59ALL                      EDDY THILLEMAN           Basm string routines     SWAG9408    ÷╥Q╝    22     ^&   πprocedure CopySubStr( Str1: string; start, nrchars: byte; var Str2: string );πassembler;π  { copy part of Str1 (beginning at start for nrchars) to Str2π    if start > length of Str1, Str2 will contain a empty string.π    if nrchars specifies more characters than remain starting at theπ    start position, Str2 will contain just that remainder of Str1. }πasmπ        { setup }π        LDS   SI,Str1      { load in DS:SI pointer to str1 }π        CLD                { string operations forward     }π        LES   DI,Str2      { load in ES:DI pointer to str2 }π        MOV   AH,[SI]      { length str1 --> AH            }π        AND   AH,AH        { length str1 = 0?              }π        JE    @null        { yes, empty string in Str2     }π        MOV   BL,[start]   { starting position --> BL      }π        CMP   AH,BL        { start > length str1?          }π        JB    @null        { yes, empty string in Str2     }ππ        { start + nrchars - 1 > length str1?               }π        MOV   AL,[nrchars] { nrchars --> AL                }π        MOV   DH,AL        { nrchars --> DH                }π        ADD   DH,BL        { add start                     }π        DEC   DHπ        CMP   AH,DH        { nrchars > rest of str1?       }π        JB    @rest        { yes, copy rest of str1        }π        JMP   #copyπ@null:π        MOV   AL,0         { return a empty string         }π        JMP   #doneπ@rest:π        SUB   AH,BL        { length str1 - start           }π        INC   AHπ        MOV   AL,AHπ@copy:π        MOV   CL,AL        { how many chars to copy        }π        XOR   CH,CH        { clear CH                      }π        XOR   BH,BH        { clear BH                      }π        ADD   SI,BX        { starting position             }π        MOV   DX,DI        { save pointer to str2          }π        INC   DIπ        REP   MOVSB        { copy part str1 to str2        }π        MOV   DI,DX        { restore pointer to str2       }π@done:π        MOV   [DI],AL      { overwrite length byte of str2 }π@exit:πend  { CopySubStr };πππprocedure StrCopy( var Str1, Str2: string ); assembler;π  { copy str1 to str2 }πasmπ        LDS   SI,Str1    { load in DS:SI pointer to str1 }π        CLD              { string operations forward     }π        LES   DI,Str2    { load in ES:DI pointer to str2 }π        XOR   CH,CH      { clear CH                      }π        MOV   CL,[SI]    { length str1 --> CX            }π        INC   CX         { include length byte           }π        REP   MOVSB      { copy str1 to str2             }π@exit:πend  { StrCopy };π                                                                                             10     08-24-9413:59ALL                      LUIS MEZQUITA            Flipping a String        SWAG9408    ÷╒ª    15     ^&   πProcedure ReverseString(var s:string);πvar i,j:byte; c:char;πbeginπ j:=Length(s);π for i:=1 to j div 2 doπ  beginπ   c:=s[i];π   s[i]:=s[j];π   s[j]:=c;π   dec(j);π  end;πend;ππ{ ---- BASM 'pointer oriented' version ------------------------------ }πProcedure ReverseAString(var s:string); assembler;πasmπ        lds SI,sπ        mov AL,[SI]π        xor AH,AHπ        mov DI,SIπ        inc SI                  { SI points to start of s }π        add DI,AX               { DI points to end of s }ππ@@0:    cmp SI,DI               { while SI=DI do ... }π        jae @@1ππ        mov AL,[SI]π        mov AH,[DI]π        mov [SI],AHπ        mov [DI],ALπ        inc SIπ        dec DIπ        jmp @@0π@@1:πend;ππ{ Version #2 }ππProcedure ReverseAString(var s:string); assembler;πasmπ                push DSπ                cldπ                lds SI,sπ                mov DI,SIπ                lodsbπ                xor AH,AHπ                add DI,AX               { DI points to end of s }π@ReverseLoop:   cmp SI,DI               { while SI=DI do ... }π                jae @ReverseExitπ                mov AL,[SI]π                mov AH,[DI]π                mov [SI],AHπ                mov [DI],ALπ                inc SIπ                dec DIπ                jmp @ReverseLoopπ@ReverseExit:   pop DSπend;ππFunction FlipStr(s:string):string; assembler;πasmπ                push DSπ                cldπ                les DI,@Resultπ                lds SI,sπ                lodsbπ                stosbπ                mov CL,ALπ                xor CH,CHπ                add DI,CXπ@FlipLoop:      and CL,CLπ                jz @FlipExitπ                lodsbπ                dec DIπ                mov ES:[DI],ALπ                dec CLπ                jmp @FlipLoopπ@FlipExit:      pop DSπend;π      11     08-24-9417:57ALL                      EDDY THILLEMAN           Byte string w/lead zero  SWAG9408    ú!╠│    12     ^&   {πFor this sort program, I needed a routine to convert a byte value into aπstring with leading zeros. So I made one in BASM: Byte2lzStr. If you want,πinclude this routine in SWAG.π}ππvar s: string;π    tel, n : byte;ππprocedure Byte2lzStr( n, width: byte; var str: string ); assembler;π  { Byte to string with leading zeros }πasmπ        std                 { string operations backwards }π        mov   al, [n]       { numeric value to convert    }π        mov   cl, [width]   { width of str                }π        xor   ch, ch        { clear ch                    }π        les   di, str       { adress of str               }π        mov   [di], cl      { length of str               }π        add   di, cx        { start with last char str    }π@start: jcxz  @exit         { done?                       }π        aam                 { divide al by 10             }π        add   al, 30h       { convert remainder to char   }π        stosb               { store digit                 }π        xchg  al, ah        { swap remainder and quotient }π        dec   cl            { count down                  }π        jmp   @start        { next digit                  }π@exit:πend  { Byte2lzStr };ππbeginπ  randomize;π  for tel := 1 to 24 doπ  beginπ    n := random( 256 );π    Byte2lzStr( n, 5, s );π    writeln( tel:2,':  ', n:3,'  ', s,'  [',length(s),']' );π  end;πend.π                                  12     08-25-9409:05ALL                      EDDY THILLEMAN           Basm routines            SWAG9408    É}~)    93     ^&   procedure CopySubStr( Str1: string; start, nrchars: byte; var Str2: string );πassembler;π  { copy part of Str1 (beginning at start for nrchars) to Str2π    if start > length of Str1, Str2 will contain a empty string.π    if nrchars specifies more characters than remain starting at theπ    start position, Str2 will contain just that remainder of Str1. }πasmπ        { setup }π        LDS   SI,Str1      { load in DS:SI pointer to str1 }π        CLD                { string operations forward     }π        LES   DI,Str2      { load in ES:DI pointer to str2 }π        MOV   AH,[SI]      { length str1 --> AH            }π        AND   AH,AH        { length str1 = 0?              }π        JE    @null        { yes, empty string in Str2     }π        MOV   BL,[start]   { starting position --> BL      }π        CMP   AH,BL        { start > length str1?          }π        JB    @null        { yes, empty string in Str2     }ππ        { start + nrchars - 1 > length str1?               }π        MOV   AL,[nrchars] { nrchars --> AL                }π        MOV   DH,AL        { nrchars --> DH                }π        ADD   DH,BL        { add start                     }π        DEC   DHπ        CMP   AH,DH        { nrchars > rest of str1?       }π        JB    @rest        { yes, copy rest of str1        }π        JMP   @copyπ@null:π        MOV   AL,0         { return a empty string         }π        JMP   @doneπ@rest:π        SUB   AH,BL        { length str1 - start           }π        INC   AHπ        MOV   AL,AHπ@copy:π        MOV   CL,AL        { how many chars to copy        }π        XOR   CH,CH        { clear CH                      }π        XOR   BH,BH        { clear BH                      }π        ADD   SI,BX        { starting position             }π        MOV   DX,DI        { save pointer to str2          }π        INC   DIπ        REP   MOVSB        { copy part str1 to str2        }π        MOV   DI,DX        { restore pointer to str2       }π@done:π        MOV   [DI],AL      { overwrite length byte of str2 }π@exit:πend  { CopySubStr };πππprocedure StrCopy( var Str1, Str2: string ); assembler;π  { copy str1 to str2 }πasmπ        LDS   SI,Str1    { load in DS:SI pointer to str1 }π        CLD              { string operations forward     }π        LES   DI,Str2    { load in ES:DI pointer to str2 }π        XOR   CH,CH      { clear CH                      }π        MOV   CL,[SI]    { length str1 --> CX            }π        INC   CX         { include length byte           }π        REP   MOVSB      { copy str1 to str2             }π@exit:πend  { StrCopy };ππfunction StrPos( var str1, str2: string ): byte; assembler;π  { returns position of the first occurrence of str1 in str2 }π  { return value in AX }π  { str1 - string to search for }π  { str2 - string to search in  }πasmπ        CLD              { string operations forward                 }π        LES   DI,Str2    { load in ES:DI pointer to str2             }π        XOR   CH,CH      { clear CH                                  }π        MOV   CL,[DI]    { length str2 --> CX                        }π        AND   CX,CX      { length str2 = 0?                          }π        JZ    @Negatief  { length str2 = 0, nothing to search in     }π        INC   DI         { make DI point to the 1st char of str2     }π        LDS   SI,Str1    { load in DS:SI pointer to str1             }π        LODSB            { load in AL length str1                    }π        AND   AL,AL      { length str1 = 0?                          }π        JZ    @Negatief  { length str1 = 0, nothing to search for    }π        MOV   AH,AL      { length str1 --> AH                        }π        DEC   AH         { 1st char need not be compared again       }π        LODSB            { load in AL 1st character of str1          }π@Start:π  REPNE SCASB            { scan for next occurrence 1st char in str2 }π        JNE   @Negatief  { no success                                }π        CMP   CL,AH      { length str1 > # chars left in str2 ?      }π        JB    @Negatief  { yes, str1 not in str2                     }π        MOV   DX,SI      { pointer to 2nd char in str1 --> DX        }π        MOV   BX,CX      { number of chars in str2 to go --> BX      }π        MOV   CL,AH      { length str1 --> CL                        }π        REPE  CMPSB      { compare until characters don't match      }π        JE    @Positief  { full match                                }π        SUB   SI,DX      { current SI - prev. SI = # of chars moved  }π        SUB   DI,SI      { reconstruct DI                            }π        MOV   SI,DX      { restore pointer to 2nd char in str1       }π        MOV   CX,BX      { number of chars in str2 to go --> BX      }π        JMP   @Start     { scan for next occurrence 1st char in str2 }π@Negatief:π        XOR   AX,AX      { str1 is not in str, result 0              }π        JMP   @Exitπ@Positief:π        XOR   AH,AH      { clear AH                                  }π        LES   DI,Str2    { load in ES:DI pointer to str2             }π        MOV   AL,[DI]    { length str2 --> AX                        }π        SUB   AX,BX      { start position of str1 in str2            }π@Exit:                   { we are finished. }πend  { StrPos };ππprocedure Trim( var Str: string ); assembler;π  { remove leading and trailing white space from str }πasmπ        { setup }π        LDS   SI,Str     { load in DS:SI pointer to Str       }π        MOV   AX,DS      { Set ES to same segment as DS       }π        MOV   ES,AX      { Set ES to same segment as DS       }π        MOV   AL,[SI]    { length Str --> AL                  }π        AND   AL,AL      { length Str = 0?                    }π        JZ    @exit      { yes, nothing to do                 }π        MOV   DI,SI      { pointer to Str --> DI              }π        MOV   AH,AL      { length Str --> AH                  }ππ        { remove trailing white space }π        XOR   CH,CH      { clear CH                           }π        MOV   CL,AH      { length Str --> CX                  }π        ADD   SI,CX      { start with last character          }π@start1:π        MOV   AL,[SI]    { character  --> AL                  }π        CMP   AL,20H     { no white space                     }π        JA    @stop1     { last non-blank character found     }π        DEC   SI         { count down SI                      }π        DEC   CL         { count down CX                      }π        AND   CL,CL      { more characters left?              }π        JZ    @stop1     { no, done                           }π        JMP   @start1    { try again                          }π@stop1:π        AND   CL,CL      { length Str = 0?                    }π        JZ    @done      { string is empty, done              }ππ        { look for leading white space }π        MOV   SI,DI      { pointer to Str --> SI              }π@start2:π        INC   SI         { next character                     }π        MOV   AL,[SI]    { character  --> AL                  }π        CMP   AL,20H     { no white space                     }π        JA    @stop2     { first non-blank character found    }π        DEC   CL         { count down                         }π        AND   CL,CL      { more characters left?              }π        JZ    @stop2     { no, done                           }π        JMP   @start2    { try again                          }π@stop2:π        MOV   DX,SI      { difference between SI and DI gives }π        SUB   DX,DI      { position first non-blank character }π        CMP   DX,1       { first character non-blank?         }π        JE    @done      { yes, done                          }ππ        { remove leading white space }π        CLD              { string operations forward          }π        MOV   BX,CX      { save length Str                    }π        MOV   DX,DI      { save pointer to Str                }π        INC   DI         { don't overwrite length byte of Str }π        REP   MOVSB      { move remaining part of Str         }π        MOV   DI,DX      { restore pointer to Str             }π        MOV   CX,BX      { restore length Str                 }π@done:π        MOV   [DI],CL    { overwrite length byte of Str       }π@exit:πend  { Trim };πππprocedure RTrim( var Str: string ); assembler;π  { remove trailing white space from str }πasmπ        { setup }π        LDS   SI,Str     { load in DS:SI pointer to Str      }π        MOV   AL,[SI]    { length Str --> AL                 }π        AND   AL,AL      { length Str = 0?                   }π        JZ    @exit      { yes, exit                         }π        MOV   DI,SI      { pointer to Str --> DI             }π        MOV   AH,AL      { length Str --> AH                 }ππ        { remove trailing space }π        STD              { SeT Direction flag --> backwards  }π        XOR   CH,CH      { clear CH                          }π        MOV   CL,AH      { length Str --> CX                 }π        ADD   SI,CX      { start with last character         }π@start:π        MOV   AL,[SI]    { character  --> AL                 }π        CMP   AL,20H     { no white space                     }π        JA    @stop      { last non-blank character found    }π        DEC   SI         { count down                        }π        DEC   CL         { count down                        }π        AND   CL,CL      { more characters left?             }π        JZ    @stop      { no, done                          }π        JMP   @start     { try again                         }π@stop:π        MOV   [DI],CL    { overwrite length byte of Str      }π@exit:πend  { RTrim };πππprocedure LTrim( var Str: string ); assembler;π  { remove leading white space from str }πasmπ        { setup }π        LDS   SI,Str     { load in DS:SI pointer to Str       }π        MOV   AL,[SI]    { length Str --> AL                  }π        AND   AL,AL      { length Str = 0?                    }π        JZ    @exit      { yes, nothing to do                 }π        MOV   DI,SI      { pointer to Str --> DI              }π        XOR   CH,CH      { clear CH                           }π        MOV   CL,AL      { length Str --> CX                  }ππ        { look for leading white space }π@start:π        INC   SI         { next character                     }π        MOV   AL,[SI]    { character  --> AL                  }π        CMP   AL,20H     { no white space                     }π        JA    @stop      { first non-blank character found    }π        DEC   CL         { count down                         }π        AND   CL,CL      { more characters left?              }π        JZ    @nullstr   { no, done                           }π        JMP   @start     { try again                          }π@nullstr:π        MOV   CL,0       { null string                        }π        JMP   @done      { we're done                         }π@stop:π        MOV   DX,SI      { difference between SI and DI gives }π        SUB   DX,DI      { position first non-blank character }π        CMP   DX,1       { first character non-blank?         }π        JE    @exit      { yes, exit                          }ππ        { remove leading white space }π        CLD              { string operations forward          }π        MOV   DX,CX      { save length Str                    }π        MOV   BX,DI      { save pointer to Str                }π        INC   DI         { don't overwrite length byte of Str }π        REP   MOVSB      { move remaining part of Str         }π        MOV   DI,BX      { restore pointer to Str             }π        MOV   CX,DX      { restore length Str                 }π@done:π        MOV   [DI],CL    { overwrite length byte of Str       }π@exit:πend  { LTrim };ππ               13     08-25-9409:08ALL                      BRIAN GRAINGER           String Dumps             SWAG9408    -~QC    32     ^&   {πLH>    Very nice - and a dandy tutorial on OOP streaming.ππThanks for the compliment.ππLH>    My little step-up speeds things up by 3x, but I imagine yours isπLH>    a hefty margin faster than that.ππI further modified the original and my streaming version to send theirπoutputs to a text file. In the original I used a variable of typeπText, and in the streaming version, I used a variable of typeπpBufStream. This was to eliminate any screen scrolling delays. I ranπboth versions on COMMAND.COM, which has a file size of 47845 bytes onπmy system. In going back over my code, I also noticed that I hadπdeclared the read buffer as vInByte: BYTE. I changed this to vInChar:πCHAR and eliminated the call to Chr(vInByte) when appending charactersπto the result string.ππThe original took 243201.838 ms and the streaming version tookπ2351.532 ms to scan the file. The absolute numbers are less importantπthan the ratio, which is 103.423. So in this instance the use ofπstreams and in-memory searching resulted in a speed-up of almost 104x.ππI tried buffer sizes of 512 to 16384 bytes in increments of 512 bytesπand found that 8192 was optimum on my system. The worst buffer sizeπwas 1024 bytes. This required 2765.426 ms to scan the file, anπincrease of 17.6% over the optimum. This was a very interesting andπunexpected result, given that 1024 is the figure used in the TV andπOWL documentation. Of course, this is probably very system dependent.πI run dual IDE drives, one formatted FAT and the other formatted OS/2πHPFS. The above results were obtained off the FAT drive. ππOn the HPFS drive, the best time was turned in by a buffer size ofπ4608 bytes. This size had given the second-best results on the FATπdrive at 2368.464 ms, but clocked in on the HPFS drive at 2373.780.πUsing an 8192 byte buffer on the HPFS drive resulted in a time ofπ2449.082 ms.ππComparing the speeds on the FAT and HPFS drives in this case isn'tπreally apples and apples, since the two drives are from differentπmanufacturers. A better test would be to use two logical partitions onπthe same drive. Even at that though the average boost in speed wasπaround 100x over the original.π}πPROGRAM FindStr;π (* Searches any file for printable strings of 6 or more characters. *)π (* Useful for extracting messages and internal documentation from .EXE's *)ππ USESπ   Objects;ππ VARπ   vInFile,π   vOutFile : pBufStream;π   vMemFile : pMemoryStream;π   vS       : STRING;π   vInChar  : CHAR;π BEGINπ   vInFile := New(pBufStream, Init(ParamStr(1), stOpenRead, 8192));π   IF vInFile = NIL THENπ     BEGINπ       WriteLn('Unable to open input file');π       Halt;π     END;π   vOutFile := New(pBufStream, Init(ParamStr(2), stCreate, 8192));π   IF vOutFile = NIL THENπ     BEGINπ       WriteLn('Unable to create output file');π       Dispose(vInFile, Done);π       Halt;π     END;π   vMemFile := New(pMemoryStream, Init(vInFile^.GetSize, 8192));π   IF vMemFile = NIL THENπ     BEGINπ       WriteLn('Insufficient memory');π       Dispose(vInFile, Done);π       Dispose(vOutfile, Done);π       Halt;π     END;π   vInFile^.Seek(0);π   vOutFile^.Seek(0);π   vMemFile^.CopyFrom(vInFile^, vInFile^.GetSize);π   IF vInFile <> NIL THENπ     Dispose(vInFile, Done);π   vMemFile^.Seek(0);π   WriteLn('>>Searching ', ParamStr(1),'<<');π   WITH vMemFile^ DOπ     WHILE (Status = stOK) DOπ       BEGINπ         vS := '';π         Read(vInChar, 1);π         WHILE ((vInChar > #31) AND (vInChar < #127) AND (Status = stOK)) DOπ           BEGINπ             vS := vS + vInChar;π             Read(vInChar, 1);π           END;π           IF Length(vS) > 5 THENπ             BEGINπ               vS := vS + #13#10;π               vOutFile^.Write(vS[1], Length(vS));π             END;π       END;π   IF vMemFile <> NIL THENπ     Dispose(vMemFile, Done);π   IF vOutFile <> NIL THENπ     Dispose(vOutFile, Done);π   WriteLn('>>End of file<<');π END.π                                                                           14     08-25-9409:08ALL                      EDDY THILLEMAN           Inline String Routines   SWAG9408    ╤√rÅ    61     ^&   {πHow do I make from a procedure or function an inline version?πIf I run the following program, the computer locks up. What's wrong??πHelp!!π}πvarπ  s1, s2: string;ππprocedure CopySubStr( Str1: string; start, nrchars: byte; var Str2: string );π  { copy part of Str1 (beginning at start for nrchars) to Str2π    if start > length of Str1, Str2 will contain a empty string.π    if nrchars specifies more characters than remain starting at theπ    start position, Str2 will contain just that remainder of Str1. }πInLine(π  $55/          {       push   bp         }π  $89/$E5/      {       mov    bp,sp      }π  $C5/$76/$0C/  {       lds    si,[bp+0C] }π  $FC/          {       cld               }π  $C4/$7E/$04/  {       les    di,[bp+04] }π  $8A/$24/      {       mov    ah,[si]    }π  $20/$E4/      {       and    ah,ah      }π  $74/$16/      {       je     @null      }π  $8A/$5E/$0A/  {       mov    bl,[bp+0A] }π  $38/$DC/      {       cmp    ah,bl      }π  $72/$0F/      {       jb     @null      }π  $8A/$46/$08/  {       mov    al,[bp+08] }π  $88/$C6/      {       mov    dh,al      }π  $00/$DE/      {       add    dh,bl      }π  $FE/$CE/      {       dec    dh         }π  $38/$F4/      {       cmp    ah,dh      }π  $72/$06/      {       jb     @rest      }π  $EB/$0A/      {       jmp    @copy      }π                { @null:                  }π  $B0/$00/      {       mov    al,00      }π  $EB/$15/      {       jmp    @done      }π                { @rest:                  }π  $28/$DC/      {       sub    ah,bl      }π  $FE/$C4/      {       inc    ah         }π  $88/$E0/      {       mov    al,ah      }π                { @copy:                  }π  $88/$C1/      {       mov    cl,al      }π  $30/$ED/      {       xor    ch,ch      }π  $30/$FF/      {       xor    bh,bh      }π  $01/$DE/      {       add    si,bx      }π  $89/$FA/      {       mov    dx,di      }π  $47/          {       inc    di         }π  $F3/$A4/      {   rep movsb             }π  $89/$D7/      {       mov    di,dx      }π                { @done:                  }π  $88/$05/      {       mov    [di],al    }π                { @exit:                  }π  $5D           {       pop    bp         }π) { CopySubStr };ππprocedure StrCopy( var Str1, Str2: string );π  { copy str1 to str2 }πInLine(π  $89/$EA/      {       mov    dx,bp      }π  $89/$E5/      {       mov    bp,sp      }π  $C5/$76/$08/  {       lds    si,[bp+08] }π  $FC/          {       cld               }π  $C4/$7E/$04/  {       les    di,[bp+04] }π  $30/$ED/      {       xor    ch,ch      }π  $8A/$0C/      {       mov    cl,[si]    }π  $41/          {       inc    cx         }π  $F3/$A4/      {   rep movsb             }π  $89/$D5       {       mov    bp,dx      }π) { StrCopy };ππfunction StrPos( var str1, str2: string ): byte;π  { returns position of the first occurrence of str1 in str2 }π  { return value in AX }π  { str1 - string to search for }π  { str2 - string to search in  }πInLine(π  $55/          {       push   bp         }π  $89/$E5/      {       mov    bp,sp      }π  $FC/          {       cld               }π  $C4/$7E/$04/  {       les    di,[bp+04] }π  $30/$ED/      {       xor    ch,ch      }π  $8A/$0D/      {       mov    cl,[di]    }π  $21/$C9/      {       and    cx,cx      }π  $74/$2A/      {       je     @negatief  }π  $47/          {       inc    di         }π  $C5/$76/$08/  {       lds    si,[bp+08] }π  $AC/          {       lodsb             }π  $20/$C0/      {       and    al,al      }π  $74/$21/      {       je     @negatief  }π  $88/$C4/      {       mov    ah,al      }π  $FE/$CC/      {       dec    ah         }π  $AC/          {       lodsb             }π                { @start:                 }π  $F2/$AE/      { repnz scasb             }π  $75/$18/      {       jne    @negatief  }π  $38/$E1/      {       cmp    cl,ah      }π  $72/$14/      {       jb     @negatief  }π  $89/$F2/      {       mov    dx,si      }π  $89/$CB/      {       mov    bx,cx      }π  $88/$E1/      {       mov    cl,ah      }π  $F3/$A6/      {   rep cmpsb             }π  $74/$0E/      {       je     @positief  }π  $29/$D6/      {       sub    si,dx      }π  $29/$F7/      {       sub    di,si      }π  $89/$D6/      {       mov    si,dx      }π  $89/$D9/      {       mov    cx,bx      }π  $EB/$E4/      {       jmp    @start     }π                { @Negatief:              }π  $31/$C0/      {       xor    ax,ax      }π  $EB/$09/      {       jmp    @exit      }π                { @Positief:              }π  $30/$E4/      {       xor    ah,ah      }π  $C4/$7E/$04/  {       les    di,[bp+04] }π  $8A/$05/      {       mov    al,[di]    }π  $29/$D8/      {       sub    ax,bx      }π                { @Exit:                  }π  $5D           {       pop    bp         }π) { StrPos };ππprocedure Trim( var Str: string );π  { remove leading and trailing white space from str }πInLine(         { setup }π  $55/          {       push   bp         }π  $89/$E5/      {       mov    bp,sp      }π  $C5/$76/$04/  {       lds    si,[bp+04] }π  $8C/$D8/      {       mov    ax,ds      }π  $8E/$C0/      {       mov    es,ax      }π  $8A/$04/      {       mov    al,[si]    }π  $20/$C0/      {       and    al,al      }π  $74/$45/      {       je     @exit      }π  $89/$F7/      {       mov    di,si      }π  $88/$C4/      {       mov    ah,al      }π              { remove trailing white space }π  $30/$ED/      {       xor    ch,ch      }π  $88/$E1/      {       mov    cl,ah      }π  $01/$CE/      {       add    si,cx      }π                { @start1:                }π  $8A/$04/      {       mov    al,[si]    }π  $3C/$20/      {       cmp    al,20      }π  $77/$09/      {       ja     @stop1     }π  $4E/          {       dec    si         }π  $FE/$C9/      {       dec    cl         }π  $20/$C9/      {       and    cl,cl      }π  $74/$02/      {       je     @stop1     }π  $EB/$F1/      {       jmp    @start1    }π                { @stop1:                 }π  $20/$C9/      {       and    cl,cl      }π  $74/$26/      {       je     @done      }π              { look for leading white space }π  $89/$FE/      {       mov    si,di      }π                { @start2:                }π  $46/          {       inc    si         }π  $8A/$04/      {       mov    al,[si]    }π  $3C/$20/      {       cmp    al,20      }π  $77/$08/      {       ja     @stop2     }π  $FE/$C9/      {       dec    cl         }π  $20/$C9/      {       and    cl,cl      }π  $74/$02/      {       je     @stop2     }π  $EB/$F1/      {       jmp    @start2    }π                { @stop2:                 }π  $89/$F2/      {       mov    dx,si      }π  $29/$FA/      {       sub    dx,di      }π  $83/$FA/$01/  {       cmp    dx,0001    }π  $74/$0C/      {       je     @done      }π  $FC/          {       cld               }π  $89/$CB/      {       mov    bx,cx      }π  $89/$FA/      {       mov    dx,di      }π  $47/          {       inc    di         }π  $F3/$A4/      {   rep movsb             }π  $89/$D7/      {       mov    di,dx      }π  $89/$D9/      {       mov    cx,bx      }π                { @done:                  }π  $88/$0D/      {       mov    [di],cl    }π                { @exit:                  }π  $5D           {       pop    bp         }π) { Trim };ππbeginπ  s1 := '123456789-123456789-';π  s2 := '';π  CopySubStr( s1, 1, 12, s2 );π  writeln( s2 );ππ  s1 := '123qqwerty';π  s2 := 'qwerty';π  CopySubStr( s1, 1, 12, s2 );π  writeln( s2 );ππ  StrCopy( s1, s2 );π  writeln( s2 );ππ  s1 := '123456789-123456789-';π  s2 := '4567';π  writeln( StrPos( s1, s2 ) );ππ  s1 := '  123qqwerty   ';π  s2 := 'qwerty';π  writeln( StrPos( s1, s2 ) );ππ  Trim( s1 );π  writeln( s2 );πend.π                    15     08-25-9409:11ALL                      EDDY THILLEMAN           RPos in BASM             SWAG9408    à&=≈    25     ^&   varπ  s1, s2: string;ππfunction RPos( var str1, str2: string ): byte; assembler;π  { returns position of the last occurrence of str1 in str2 }π  { return value in AX }π  { str1 - string to search for }π  { str2 - string to search in  }πasmπ        STD              { string operations backwards               }π        LES   DI,Str2    { load in ES:DI pointer to str2             }π        XOR   CH,CH      { clear CH                                  }π        MOV   CL,[DI]    { length str2 --> CX                        }π        AND   CX,CX      { length str2 = 0?                          }π        JZ    @Negatief  { length str2 = 0, nothing to search in     }π        ADD   DI,CX      { make DI point to the last char of str2    }π        LDS   SI,Str1    { load in DS:SI pointer to str1             }π        XOR   AH,AH      { clear AH                                  }π        MOV   AL,[SI]    { load in AX length str1                    }π        AND   AL,AL      { length str1 = 0?                          }π        JZ    @Negatief  { length str1 = 0, nothing to search for    }π        ADD   SI,AX      { make SI point to the last char of str1    }π        MOV   AH,AL      { length str1 --> AH                        }π        DEC   AH         { last char need not be compared again      }π        LODSB            { load in AL last character of str1         }π@Start:π  REPNE SCASB            { scan for next occurrence 1st char in str2 }π        JNE   @Negatief  { no success                                }π        CMP   CL,AH      { length str1 > # chars left in str2 ?      }π        JB    @Negatief  { yes, str1 not in str2                     }π        MOV   DX,SI      { pointer to last but 1 char in str1 --> DX }π        MOV   BX,CX      { number of chars in str2 to go --> BX      }π        MOV   CL,AH      { length str1 --> CL                        }π   REPE CMPSB            { compare until characters don't match      }π        JE    @Positief  { full match                                }π        SUB   SI,DX      {                                           }π        NEG   SI         { prev. SI - current SI = # of chars moved  }π        ADD   DI,SI      { reconstruct DI                            }π        MOV   SI,DX      { restore pointer to 2nd char in str1       }π        MOV   CX,BX      { number of chars in str2 to go --> BX      }π        JMP   @Start     { scan for next occurrence 1st char in str2 }π@Negatief:π        XOR   AX,AX      { str1 is not in str, result 0              }π        JMP   @Exitπ@Positief:π        INC   BLπ        SUB   BL,AH      { start position of str1 in str2            }π        MOV   AL,BL      { in AL                                     }π        XOR   AH,AH      { clear AH                                  }π@Exit:                   { we are finished. }πend  { RPos };ππbeginπ  s1 := ParamStr( 1 );π  s2 := ParamStr( 2 );π  writeln( RPos( s1, s2 ) );πend.ππ{πIf a '#' (shift-3) appears in the assembler source code, please replaceπthat by a at-sign (shift-2).π}                           16     08-25-9409:12ALL                      JOSE CAMPIONE            FASTEST Uppercase        SWAG9408    rÉσ1    24     ^&   π   (*ππ   For the SWAGS...ππ   To the best of my knowledge this is the fastest routine for π   up/low-casing strings in Turbo Pascal. The difference from π   previous versions is that it uses seges for segment override π   and within the loop it replaces loadsb and stosb with mov π   operations. It is also independent from the segment in which π   Source and Table are created. π   π   If anyone finds a bug or has a suggestion, or has a faster π   looking routine for string translations, just leave me a π   message here. I'll benchmark the new routine against the π   collection I have gathered already from the SWAGS and π   elsewhere and will post the results. ππ   The following benchmarking was done in a 486/DX 60 MHz using π   Neil Rubenking's TimeTick unit while upcasing a full string π   (255 chars) 400,000 times (100 million characters): ππ   For-Do loop using TP7 UpCase() .......... 315.5 secs.π   UpperCase (Assembler classical approach)   53.9 secs. (1)π   My old TXlat3 ...........................  28.3 secs. (2)π   Translate ...............................  26.8 secs. (3)π   TXlat5 (the one in this message) ........  21.2 secs.ππ   (1) There are several routines using this approach in the π       SWAGS. See also HAX 144 in PC-Techniques. π   (2) See "St-case4.pas" in STRINGS.SWG, it contains an earlier π       (and buggy...) version.π   (3) See "Translate upper/lower case" in STRINGS.SWGππ   -Jose-π   Jose Campione, 1:163.513.3π   *)ππ    Program TXlate;ππ    typeπ      ByteArray = array[0..255] of byte;π    varπ      Source  : string;π      Table   : ByteArray;π      i       : byte;ππ    Procedure TXlat5(var Source: string; var Table: ByteArray);assembler;π    asmπ        mov  dx, ds       { save ds }π        lds  bx,Table     { load ds:bx with Table address }π        les  di,Source    { load es:di with Source address }π        seges             { override ds segment}π        mov  al,[di]      { load al with length of source }π        xor  ah, ah       { set ah to zero, we need a word for cx }π        mov  cx,ax        { assign length of source to counter }π        jcxz @end         { if cx = 0 exit}π        inc  di           { increment di & skip length byte on 1st pass }π      @filter:π        mov  al,[di]      { load byte in ax from es:di }π        xlat              { tan-xlat-e... }π        mov  [di],al      { send byte to es:di }π        inc  di           { increment di }π        loop @filter      { decrement cx and loop back if cx > 0 }π      @end: mov  ds, dx   { restore ds }π    end;ππ    beginπ      {...}π      {Fill Table for UpCase translation}π      for i:= 0 to 255 doπ        if i in [$61..$7A] then Table[i]:= i - $20 else Table[i]:= i;π      {...}π      Source: 'this string is to be upcased ';π      WriteLn(Source);π      TXlat5(Source,Table);π      WriteLn(Source);π      {...}π    end.ππ   π                                                                              17     08-25-9409:12ALL                      EDDY THILLEMAN           Trim Strings             SWAG9408    I╪ò    50     ^&   πprocedure White2Space( var Str: string; const WhiteSpace: string ); assembler;π  { replace white space chars in Str by spacesπ    the string WhiteSpace contains the chars to replace }πasm     { setup }π        cld                      { string operations forwards    }π        les   di, str            { ES:DI points to Str           }π        xor   cx, cx             { clear cx                      }π        mov   cl, [di]           { length Str in cl              }π        jcxz  @exit              { if length of Str = 0, exit    }π        inc   di                 { point to 1st char of Str      }π        mov   dx, cx             { store length of Str           }π        mov   bx, di             { pointer to Str                }π        lds   si, WhiteSpace     { DS:SI points to WhiteSpace    }π        mov   ah, [si]           { load length of WhiteSpace     }ππ@start: cmp   ah, 0              { more chars WhiteSpace left?   }π        jz    @exit              { no, exit                      }π        inc   si                 { point to next char WhiteSpace }π        mov   al, [si]           { next char to hunt             }π        dec   ah                 { ah counting down              }π        xor   dh, dh             { clear dh                      }π        mov   cx, dx             { restore length of Str         }π        mov   di, bx             { restore pointer to Str        }π        mov   dh, ' '            { space char                    }π@scan:π  repne scasb                    { the hunt is on                }π        jnz   @next              { white space found?            }π        mov   [di-1], dh         { yes, replace that one         }π#next:  jcxz  @start             { if no more chars in Str       }π        jmp   @scan              { if more chars in Str          }π@exit:πend  { White2Space };πππprocedure Trim( var Str: string ); assembler;π  { remove trailing and leading spaces from str }πasm     { setup }π        les   di, str            { ES:DI points to Str                }π        lds   si, str            { DS:SI points to Str                }π        xor   cx, cx             { clear cx                           }π        mov   cl, [di]           { length Str in cl                   }π        jcxz  @exit              { if length of Str = 0, exit         }π        mov   bx, di             { bx points to length byte of Str    }π        xor   dx, dx             { clear dx                           }π        mov   al, ' '            { hunt for spaces                    }ππ        { look for trailing spaces }π        std                      { string operations backwards        }π        add   di, cx             { start with last char in Str        }π   repe scasb                    { the hunt is on                     }π        jz    @done              { only spaces?                       }π        inc   cx                 { no, don't lose last char           }ππ        { look for leading spaces }π        cld                      { string operations forward          }π        inc   si                 { pointer to 1st char of Str         }π        mov   di, si             { pointer to 1st char of Str --> di  }π   repe scasb                    { the hunt is on                     }π        jz    @done              { if only spaces, we are done        }π        inc   cx                 { no, don't lose 1st non-blank char  }π        dec   di                 { no, don't lose 1st non-blank char  }π        mov   dx, cx             { new lenght of Str                  }π        xchg  di, si             { swap si and di                     }π    rep movsb                    { move remaining part of Str         }π@done:  mov   [bx], dl           { new length of Str                  }π@exit:πend  { Trim };ππprocedure RTrim( var Str: string ); assembler;π  { remove trailing spaces from str }πasm     { setup }π        std                      { string operations backwards   }π        les   di, str            { ES:DI points to Str           }π        xor   cx, cx             { clear cx                      }π        mov   cl, [di]           { length Str in cl              }π        jcxz  @exit              { if length of Str = 0, exit    }π        mov   bx, di             { bx points to Str              }π        add   di, cx             { start with last char in Str   }π        mov   al, ' '            { hunt for spaces               }ππ        { remove trailing spaces }π   repe scasb                    { the hunt is on                }π        jz    @done              { only spaces?                  }π        inc   cx                 { no, don't lose last char      }π@done:  mov   [bx], cl           { overwrite length byte of Str  }π@exit:πend  { RTrim };πππprocedure LTrim( var Str: string ); assembler;π  { remove leading white space from str }πasm     { setup }π        cld                      { string operations forward          }π        lds   si, str            { DS:SI points to Str                }π        xor   cx, cx             { clear cx                           }π        mov   cl, [si]           { length Str --> cl                  }π        jcxz  @exit              { if length Str = 0, exit            }π        mov   bx, si             { save pointer to length byte of Str }π        inc   si                 { 1st char of Str                    }π        mov   di, si             { pointer to 1st char of Str --> di  }π        mov   al, ' '            { hunt for spaces                    }π        xor   dx, dx             { clear dx                           }ππ        { look for leading spaces }π   repe scasb                    { the hunt is on                     }π        jz    @done              { if only spaces, we are done        }π        inc   cx                 { no, don't lose 1st non-blank char  }π        dec   di                 { no, don't lose 1st non-blank char  }π        mov   dx, cx             { new lenght of Str                  }π        xchg  di, si             { swap si and di                     }π    rep movsb                    { move remaining part of Str         }π@done:  mov   [bx], dl           { new length of Str                  }π@exit:πend  { LTrim };ππ                                                  18     08-26-9407:26ALL                      BRUCE J. LACKORE         Boolean String Search    SWAG9408    ╦ÿüü    246    ^&   Unit BoolPos;π{$Define Test}π{        Once debugging is complete, remove the above line to turn off debug mode. }ππ{        Version 1.3.5.P.ππ        Requires Borland Turbo Pascal version 6.0 or later to compile.ππ        Author:  Bruce J. Lackore.  Created Friday, July 23, 1993.π        Copyright (c) 1993 Bruce J. Lackore.  ALL RIGHTS RESERVED.π}ππ{$IFDEF Test}π        {$A+,B-,D+,F-,G-,I+,L+,O-,R+,S+,V-,X+}π{$ELSE}π        {$A+,B-,D-,F-,G-,I-,L-,O-,R-,S-,V-,X+}π{$ENDIF}ππ{        This unit comprises a function capable of searching a string for multipleπ        occurences of substrings using Boolean operators.  In the search string,π        Boolean operators And and Or are defined as follows:ππ                & - Andπ                | - Orππ        Parentheses are supported for doing multiple searches.  Search strings areπ        submitted as follows:ππ                i.e. In the source string "The quick brown fox jumped over the lazy dog"π                                        and the search is for the word blue and the words quick or fox,π                                        the search string is entered as follows:ππ                                                (blue&(quick|fox))ππ        The way the function is currently written, And (&) and Or (|) have the sameπ        precedence level hence the above search string without parentheses would beπ        interpretted to be (blue&quick|fox):ππ                blue And quick would be searched for first, the result Or'd with theπ                results of the search for fox.ππ        Notice the difference in that (blue&(quick|fox)) is a False statement whilstπ        (blue&quick|fox) is True.ππ        The function will automatically scan for () pairs, adding the necessary )π        at the end of the search string or ( at the beginning if required.ππ        The function will also search for (|, |), (& and &) symbols, these beingπ        illegal.ππ        It should also be noted that although excess parens will not cause theπ        function to fail, they DO cause the function to loop unnecessarily throughπ        the token search (once for each set of parens) while bringing the finalπ        answer out of the final set of parens.ππ}ππ{        Bug fixes:ππ                07/04/1994: Thought the 06/01 fix did the job.  It didn't.  This time,π                                                                I went back into the token processor and found that it wasπ                                                                missing a left paren when the tokenized search string was inπ                                                                the form of (b@b...)@(b@b...) where b is a boolean designatorπ                                                                (T or F) and @ is a boolean operator (| or &).  Thanx toπ                                                                Michael Jarmulowicz for pointing this out.π                                                                The fix was to go into the Process_token_str function andπ                                                                ensure that a multi-pass required token string has sufficientπ                                                                parens so as to not confuse the token processor.π                                                                Also defined BPos return value should the Fixup_srch_strπ                                                                function fail.  The default is False (as set in the firstπ                                                                line of the BPos function itself) and is triggered byπ                                                                Fixup_srch_str returning a null string.  Removed the "fix"π                                                                that was suggested in the 06/01 bug fix and replaced it withπ                                                                code that scans the first and last letters of the Srch_strπ                                                                to ensure that they are parens, if not, add a pair.ππ                06/01/1994: After returning from WestPac, I received a couple of emailsπ                                                                telling me that if the function was called with NOπ                                                                parentheses, it would fail.  The fix is simply to add a set ofπ                                                                parens in the Fixup_srch_str function just before theπ                                                                function returns if the first character of the Srch_str is NOTπ                                                                a left paren equivalent.  I have had one report of the unitπ                                                                not working in protected mode.  As I don't yet know much aboutπ                                                                protected mode programming, I am still working on thatπ                                                                particular bug but I WILL fix it if the error is in here.  Iπ                                                                also tightened up one of the assembly replacement functions,π                                                                see the docs for the change.ππ                10/04/1993:        Noticed that length of Src_str in function Next_CPos wasπ                                                                incorrectly calculated because of positioning of INC DI.π                                                                INC DI precedes the MOV CL,[ES:DI] causing the function toπ                                                                consider the first character of Src_str to represent theπ                                                                length rather than the actual length byte.  Fix is to moveπ                                                                the INC DI to the line following the MOV CL,[ES:DI].ππ}ππInterfaceππFunction BPos(Srch_str, Src_str:  String;  Ignore_case:  Boolean):  Boolean;ππ{        This function accepts a source string and a search string as described aboveπ        and returns a Boolean value based on whether or not the parsed searchπ        string was found.π}ππ{ ************************************************************************** }ππImplementationππConstπ        Lt_pn:                                                                                Char = '(';π        Rt_pn:                                                                                Char = ')';ππFunction Cnt_ch(Scan_char:  Char;  In_str:  String):  Byte;  Assembler;ππ{        This function will scan a string for occurences of a particular character.π        The function will return the number of occurences.π}ππ        Asm  { Function Cnt_ch }π                                                        XOR                AX,AX                                        {        0 AX }π                                                        MOV                BL,Scan_char  {        Put char to count in BL }π                                                        LES                SI,In_str     {        Set ES:SI to point to start of string }π                                                        XOR                CX,CX         {        0 CX }π                                                        MOV                CL,[ES:SI]    {        Move string length to CX }π                                                        ADD                SI,CX         {        Set ES:SI to point to END of string }π                @LOOK:                CMP                BL,[ES:SI]    {        Start Loop, compare current char and BL }π                                                        JNE                @NEXT         {        If not equal, jump to end of loop }π                                                        INC                AX            { If equal, Inc char cnt (AX) }π                @NEXT:                DEC                SI            {        Set ES:SI back one character }π                                                        LOOP        @LOOK         {        Decrement CX and jump to start of loop }π        End;  { Function Cnt_ch }ππFunction Fill_str(Dupe_ch:  Char;  How_many:  Byte):  String;  Assembler;ππ{        This function returns How_many of Dupe_char.π}ππ        Asm  { Function Fill_str }π                                                        LES                DI, @Result                {        Set ES:DI to function result area }π                                                        CLD                 {        Clear direction flag }π                                                        XOR         CH,CH         {        0 CH }π                                                        MOV         CL,How_many          { Length in CX }π                                                        MOV         AX,CX                { and in AX }π                                                        STOSB                     { Store length byte }π                                                        MOV         AL,Dupe_ch    {        Put char to dupe in AL }π                                                        REP         STOSB         { Fill string with char }π        End;  { Function Fill_str }ππFunction PosC(Srch_ch:  Char;  Src_str:  String):  Boolean;  Assembler;ππ{        This function is similar to the Pos function of Pascal except that itπ        accepts only a single character to search for.  This function returns aπ        True if a Srch_ch is encountered, a False if not.π}ππ        Asm  { Function PosC }π                                                        XOR                BX,BX                                        {        0 BX }π                                                        MOV                AL,Srch_ch    {        Put char to look for in AL }π                                                        LES                DI,Src_str    {        Set ES:DI to start of Src_str }π                                                        XOR                CX,CX         {        0 CX }π                                                        MOV                CL,[ES:DI]    {        Store length of Src_str in CL }π                                                        ADD                DI,CX         {        Set ES:DI to end of string }π                                                        STD                 {        Set direction flag }π                @LOOK:                REPNZ        SCASB         {        Look for AL in Src_str }π                                                        JNZ                @DONE         {        If not found, jump to end (BX = 0) }π                                                        INC                BX            {        If Found, Inc Bx  to 1 = Pascal True }π                @DONE:                MOV                AX,BX         {        Move BX to AX (return result) }π        End;  { Function PosC }ππFunction Last_Cpos(Srch_ch:  Char;  Src_str:  String):  Byte;  Assembler;ππ{        This function performs the same function as the Pascal POS function exceptπ        that it works only with a single character and rather than returning theπ        first position the character is found in, it returns the LAST position thatπ        the search character is found in.π}ππ        Asm { Function Last_Cpos }π                                                        MOV                AL,Srch_ch                {        Put char to look for in AL }π                                                        LES                DI,Src_str    {        Set ES:DI to start of Src_str }π                                                        XOR                CX,CX         {        0 CX }π                                                        MOV                CL,[ES:DI]    {        Move length of Src_str to CL }π                                                        ADD                DI,CX         {        Set ES:DI to end of Src_str }π                                                        INC                CX            { Add one to CX (correct for string length }π                                                        STD                 {        Set direction flag }π                                                        REPNZ        SCASB         {        Look for character in string }π                                                        MOV                AX,CX         { If found CX indicates position, else 0 }π        End;  { Function Last_Cpos }ππFunction Next_CPosπ        (Srch_ch:  Char;  Src_str:  String;  Strt_at:  Byte):  Byte;  Assembler;ππ{        This function searches for the next occurence of Srch_ch in Src_str AFTERπ        position Strt_at.  The function returns the offset from the beginning ofπ        the string, NOT the offset from Strt_at.π}ππ        Asm  { Function Next_CPos }π                                                        XOR                AX,AX         {        0 AX }π                                                        MOV                AL,Strt_at    {        Move position to start at to AL }π                                                        LES                DI,Src_str    {        Set ES:DI to start of Src_str }π                                                        XOR                CX,CX         {        0 CX }π                                                        MOV                CL,[ES:DI]    {        Store length of Src_str in CL }π                                                        INC                DI            {        Set ES:DI to first char of Src_str }π                                                        MOV                BX,CX         {        Move CX to BX }π                                                        SUB                CX,AX         {        Set CX to length of string after Strt_at }π                                                        ADD                DI,AX         {        Set ES:DI to char at Strt_at in Src_str }π                                                        MOV                AL,Srch_ch    {        Move Srch_ch to AL }π                                                        CLD                 {        Clear direction flag }π                                                        REPNZ        SCASB         {        Look for character following Strt_at }π                                                        JNZ                @NOTFND       {        If not found, jump to end of procedure }π                                                        SUB                BX,CX         {        Set BX to position char found in }π                                                        JMP                @DONE         {        Jump to end of procedure }π                @NOTFND:        XOR                BX,BX         {        Srch_ch not found, set BX to 0 }π                @DONE:                MOV                AX,BX         {        Move position found at (BX) to AX }π        End;  { Function Next_CPos }ππ{$F+}πFunction Up_cs(In_str:  String):  String;ππ{        This function converts In_str to all upper case characters.π}ππ        Begin  { Function Up_cs }π                Inline(π                        $1E/                                                                {                                        PUSH DS  }π                        $C4/$7E/$0A/                                {                                        LES         DI,[BP+$0A]  }π                        $C5/$76/$06/                                {                                        LDS         SI,[BP+$06]  }π                        $30/$E4/                                                {                                        XOR         AH,AH  }π                        $AC/                                                                {                                        LODSB  }π                        $AA/                                                                {                                        STOSB  }π                        $89/$C1/                                                {                                        MOV         CX,AX  }π                        $E3/$0F/                                                {                                        JCXZ DONE  }π                        $FC/                                                                {                                        CLD  }π                        $AC/                                                                {DOCHAR:        LODSB  }π                        $3C/$61/                                                {                                        CMP         AL,'a'  }π                        $72/$06/                                                {                                        JB         NEXTCH  }π                        $3C/$7A/                                                {                                        CMP         AL,'z'  }π                        $77/$02/                                                {                                        JA         NEXTCH  }π                        $24/$DF/                                                {                                        AND         AL,$DF  }π                        $AA/                                                                {NEXTCH:        STOSB  }π                        $E2/$F2/                                                {                                        LOOP DOCHAR  }π                        $1F)                                                                {DONE:                POP         DS  }π        End;  { Function Up_cs }π{$F-}ππFunction Fixup_srch_str(Srch_str:  String):  String;ππ{        This functions sole purpose in life is to count the number of paranthesesπ        pairs and correct for a deficient number of either by adding the appropriateπ        character either at the beginning or the end of the search string.  Thisπ        may not yield the correct result as the searcher intended but is aπ        requirement of the algorithm (it searches for paran pairs).  Note that theπ        function will add one set of parantheses if none are found.  This functionπ        also looks for illegal character pairs (&, &), (| and |), these pairsπ        indicate an illegal Boolean search.  The function returns the correctedπ        Srch_str if all is well, an empty string if not.π}ππ        Varπ                Left_para,π                Right_para,π                How_many:                                                                Integer;ππ        Begin  { Function Fixup_srch_str }π                If (Srch_str[Length(Srch_str)] <> Rt_pn) Or (Srch_str[1] <> Lt_pn) Thenπ                        Srch_str := Lt_pn + Srch_str + Rt_pn;π                Left_para         := Cnt_ch(Lt_pn, Srch_str);                                        {        Count the parens }π                Right_para         := Cnt_ch(Rt_pn, Srch_str);π                How_many                 := Abs(Left_para - Right_para);     { Get the difference }π                If How_many > 0 Thenπ                        If Right_para < Left_para Thenπ                                Srch_str := Srch_str + Fill_str(Rt_pn, How_many)π                        Elseπ                                Srch_str := Fill_str(Lt_pn, How_many) + Srch_str;π                If (Pos(Lt_pn + '&', Srch_str) <> 0) Or         { Illegal call? }π                        (Pos('&' + Rt_pn, Srch_str) <> 0) Orπ                        (Pos(Lt_pn + '|', Srch_str) <> 0) Orπ                        (Pos('|' + Rt_pn, Srch_str) <> 0) Thenπ                                Fixup_srch_str := ''π                Elseπ                        Fixup_srch_str := Srch_str                                                                                {        All is well }π        End;  { Function Fixup_srch_str }ππFunction Parse_srch_str(Srch_str, Src_str:  String):  String;ππ{        This function simply extracts each string to search for, tests to see ifπ        it exists in the original string and replaces the extracted substring withπ        the appropriate token.  It should be noted that each substring is determinedπ        solely by the characters used for parantheses and operators.  Any otherπ        characters are assumed to be part of the search string.ππ        Each substring is searched for in the original Search_str and its presenseπ        or absense noted with a T or F respectively.π}ππ        Varπ                Rtn_str,π                Token_str:                                                        String;π                End_token:                                                        Boolean;ππ        Begin  { Function Parse_srch_str }π                Token_str         := '';π                Rtn_str                        := '';π                While Srch_str <> '' Doπ                        Beginπ                                If (Srch_str[1] In [Lt_pn, Rt_pn, '&', '|']) Then { Token starts? }π                                        Beginπ                                                End_token := (Token_str <> '');       { End of token?  If not }π                                                If Not(End_token) Then                { then start one.       }π                                                        Rtn_str := Rtn_str + Srch_str[1]π                                        Endπ                                Elseπ                                        Beginπ                                                Token_str := Token_str + Srch_str[1]; { Add a char to substring }π                                                End_token        := Falseπ                                        End;π                                If End_token Then                         { If complete token, look }π                                        Begin                                   { for it in the source str }π                                                If Pos(Token_str, Src_str) <> 0 Thenπ                                                        Rtn_str := Rtn_str + 'T'            { If found, return T }π                                                Elseπ                                                        Rtn_str := Rtn_str + 'F';           { If not, return F   }π                                                Rtn_str         := Rtn_str + Srch_str[1];π                                                Token_str := '';                      { Reset to look for more }π                                                End_token        := Falseπ                                        End;  { If End_token }π                                Delete(Srch_str, 1, 1)                    { Delete the char justπ                                                                                                                                                                                                                processed and start againπ                                                                                                                                                                                                        }π                        End;  { While Srch_str <> '' }π                Parse_srch_str := Rtn_strπ        End;  { Function Parse_srch_str }ππFunction Process_token_str(Token_str:  String):  Char;ππ        Varπ                One_token:                                                        String;π                One_token_len,π                Left_para:                                                        Byte;ππ        Function Process_one_token_str(The_token:  String):  Char;ππ                Varπ                        Lcv:                                                                        Byte;π                        Curr_answer,π                        Do_and:                                                                Boolean;ππ                Begin  { Function Process_one_token_str }π                        Curr_answer := (The_token[1] = 'T');      { Establish current answerπ                                                                                                                                                                                                        by checking first token.π                                                                                                                                                                                                }π                        For Lcv := 2 to Length(The_token) Do      { Look at the rest of theπ                                                                                                                                                                                                        token str.π                                                                                                                                                                                                }π                                Case The_token[Lcv] of                  { Boolean op is And }π                                        '&':        Do_and := True;                 { Boolean op is Or }π                                        '|':        Do_and := False;π                                        'T':        If Do_and Thenπ                                                                        Curr_answer := Curr_answer And True  { If And }π                                                                Elseπ                                                                        Curr_answer := True;                 { If Or }π                                        'F':        If Do_and Then                         { If And (Or stays T) }π                                                                        Curr_answer := False;π                                End;  { Case }π                        If Curr_answer Then                      { Final result }π                                Process_one_token_str := 'T'π                        Elseπ                                Process_one_token_str        := 'F'π                End;  { Function Process_one_token_str }ππ        Begin  { Function Process_token_str }ππ                { Are parens present?  If so process as tokenized phrase, if not, finalπ                        result has been received or can be processed in a single pass.π                }ππ                If PosC(Lt_pn, Token_str) Thenπ                        Beginπ                                While Length(Token_str) > 1 Doπ                                        Beginππ                                                {        Ensure that the token has enough parens to not confuse theπ                                                        token string processor.  One need only check for a left parenπ                                                        since the Fixup_srch_str function ensures that an equal numberπ                                                        of paren PAIRS exists.π                                                }ππ                                                If Not(PosC(Lt_pn, Token_str)) Thenπ                                                        Token_str := Lt_pn + Token_str + Rt_pn;ππ                                                { Find leftmost left paren }ππ                                                Left_para                 := Last_Cpos(Lt_pn, Token_str);πππ                                                { Find first right paren after leftmost left paren }ππ                                                One_token_len :=π                                                        Succ(Next_CPos(Rt_pn, Token_str, Left_para) - Left_para);ππ                                                { Copy everything between the two }ππ                                                One_token := Copy(Token_str, Left_para, One_token_len);ππ                                                { Remove the parens }ππ                                                Dec(One_token[0]);π                                                Delete(One_token, 1, 1);ππ                                                { Remove the original substring from the phrase }ππ                                                Delete(Token_str, Left_para, One_token_len);ππ                                                { Insert the resultant single character in place of the oldπ                                                        substring.π                                                }ππ                                                Insert(Process_one_token_str(One_token), Token_str, Left_para)π                                        End;  { While Length(Token_str) > 1 }π                                Process_token_str := Token_str[1]π                        Endπ                Elseπ                        Process_token_str := Process_one_token_str(One_token)π        End;  { Function Process_token_str }ππFunction BPos;ππ        Begin  { Function BPos }π                BPos := False;π                If Ignore_case Thenπ                        Beginπ                                Srch_str         := Up_cs(Srch_str);π                                Src_str   := Up_cs(Src_str)π                        End;  { If Ignore_case }ππ                {        Is this a Boolean expression?  If so process with this function, elseπ                        process with Pascal POS function.π                }ππ                If PosC('|', Srch_str) Or PosC('&', Srch_str) Thenπ                        Beginπ                                Srch_str := Parse_srch_str(Fixup_srch_str(Srch_str), Src_str);π                                If Srch_str <> '' Thenπ                                        BPos := (Process_token_str(Srch_str) = 'T')π                        Endπ                Elseπ                        BPos := Pos(Srch_str, Src_str) <> 0π        End;  { Function BPos }ππEnd.  { Unit BoolPos }ππProgram Test;π{$Define test}ππ{        Version 1.0.0.Tππ        Requires Borland Turbo Pascal version 6.0 or later to compile.ππ        Author:  Bruce J. Lackore.  Created Monday, June 13, 1994.π        Copyright (c) 1994 Bruce J. Lackore.  ALL RIGHTS RESERVED.π}ππ{$IFDEF Test}π        {$A+,B-,D+,E+,F-,G-,I+,L+,N-,R+,S+,V-,X+}π{$ELSE}π        {$A+,B-,D-,E+,F-,G-,I-,L-,N-,R-,S-,V-,X+}π{$ENDIF}ππ{$M 16384, 0, 655360}ππ{        This is a quick and really dirty test program for the Boolpos unit.  Justπ        tinker with the search phrase in line 3 of the code and enjoy!π}ππUses Boolpos;ππVarπ        BResult: Boolean;π        Src_str: String;ππProcedure Start_program;ππ        Begin  { Procedure Start_program }π                BResult := False;π                Src_str        := 'Now is the time for all good programmers to switch to OS/2';π                BResult := BPos('(Now&then)|(time&bad)', Src_str, False)π        End;  { Procedure Start_program }ππBegin  { Program:  Test }π        Start_program;πEnd.  { Program:  Test }